home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * quadrics.c
- *
- * This module implements the code for the quadric shape primitive.
- *
- * from Persistence of Vision Raytracer
- * Copyright 1993 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file. If
- * POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- * Forum. The latest version of POV-Ray may be found there as well.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "vector.h"
- #include "povproto.h"
-
- METHODS Quadric_Methods =
- {
- All_Quadric_Intersections,
- Inside_Quadric, Quadric_Normal,
- Copy_Quadric,
- Translate_Quadric, Rotate_Quadric,
- Scale_Quadric, Transform_Quadric, Invert_Quadric,
- Destroy_Quadric
- };
-
- extern RAY *CM_Ray;
- extern long Ray_Quadric_Tests, Ray_Quadric_Tests_Succeeded;
-
- int All_Quadric_Intersections (Object, Ray, Depth_Stack)
- OBJECT *Object;
- RAY *Ray;
- ISTACK *Depth_Stack;
- {
- DBL Depth1, Depth2;
- VECTOR IPoint;
- register int Intersection_Found;
-
- Intersection_Found = FALSE;
-
- if (Intersect_Quadric (Ray, (QUADRIC *) Object, &Depth1, &Depth2))
- {
- VScale (IPoint, Ray->Direction, Depth1);
- VAddEq (IPoint, Ray->Initial);
-
- if (Point_In_Clip (&IPoint, Object->Clip))
- {
- push_entry(Depth1,IPoint,Object,Depth_Stack);
- Intersection_Found = TRUE;
- }
-
- if (Depth2 != Depth1)
- {
- VScale (IPoint, Ray->Direction, Depth2);
- VAddEq (IPoint, Ray->Initial);
-
- if (Point_In_Clip (&IPoint, Object->Clip))
- {
- push_entry(Depth2,IPoint,Object,Depth_Stack);
- Intersection_Found = TRUE;
- }
- }
- }
- return (Intersection_Found);
- }
-
- int Intersect_Quadric (Ray, Quadric, Depth1, Depth2)
- RAY *Ray;
- QUADRIC *Quadric;
- DBL *Depth1, *Depth2;
- {
- register DBL Square_Term, Linear_Term, Constant_Term, Temp_Term;
- register DBL Determinant, Determinant_2, A2, BMinus;
-
- Ray_Quadric_Tests++;
- if (!Ray->Quadric_Constants_Cached)
- Make_Ray(Ray);
-
- if (Quadric->Non_Zero_Square_Term)
- {
- VDot (Square_Term, Quadric->Square_Terms, Ray->Direction_2);
- VDot (Temp_Term, Quadric->Mixed_Terms, Ray->Mixed_Dir_Dir);
- Square_Term += Temp_Term;
- }
- else
- Square_Term = 0.0;
-
- VDot (Linear_Term, Quadric->Square_Terms, Ray->Initial_Direction);
- Linear_Term *= 2.0;
- VDot (Temp_Term, Quadric->Terms, Ray->Direction);
- Linear_Term += Temp_Term;
- VDot (Temp_Term, Quadric->Mixed_Terms, Ray->Mixed_Init_Dir);
- Linear_Term += Temp_Term;
-
- if (Ray == CM_Ray)
- if (!Quadric->Constant_Cached)
- {
- VDot (Constant_Term, Quadric->Square_Terms, Ray->Initial_2);
- VDot (Temp_Term, Quadric->Terms, Ray->Initial);
- Constant_Term += Temp_Term + Quadric->Constant;
- Quadric->CM_Constant = Constant_Term;
- Quadric->Constant_Cached = TRUE;
- }
- else
- Constant_Term = Quadric->CM_Constant;
- else
- {
- VDot (Constant_Term, Quadric->Square_Terms, Ray->Initial_2);
- VDot (Temp_Term, Quadric->Terms, Ray->Initial);
- Constant_Term += Temp_Term + Quadric->Constant;
- }
-
- VDot (Temp_Term, Quadric->Mixed_Terms,
- Ray->Mixed_Initial_Initial);
- Constant_Term += Temp_Term;
-
- if (Square_Term != 0.0)
- {
- /* The equation is quadratic - find its roots */
-
- Determinant_2 = Linear_Term * Linear_Term - 4.0 * Square_Term * Constant_Term;
-
- if (Determinant_2 < 0.0)
- return (FALSE);
-
- Determinant = sqrt (Determinant_2);
- A2 = Square_Term * 2.0;
- BMinus = Linear_Term * -1.0;
-
- *Depth1 = (BMinus + Determinant) / A2;
- *Depth2 = (BMinus - Determinant) / A2;
- }
- else
- {
- /* There are no quadratic terms. Solve the linear equation instead. */
- if (Linear_Term == 0.0)
- return (FALSE);
-
- *Depth1 = Constant_Term * -1.0 / Linear_Term;
- *Depth2 = *Depth1;
- }
-
- if ((*Depth1 < Small_Tolerance) || (*Depth1 > Max_Distance))
- if ((*Depth2 < Small_Tolerance) || (*Depth2 > Max_Distance))
- return (FALSE);
- else
- *Depth1 = *Depth2;
- else
- if ((*Depth2 < Small_Tolerance) || (*Depth2 > Max_Distance))
- *Depth2 = *Depth1;
-
- Ray_Quadric_Tests_Succeeded++;
- return (TRUE);
- }
-
- int Inside_Quadric (IPoint, Object)
- VECTOR *IPoint;
- OBJECT *Object;
- {
- QUADRIC *Quadric = (QUADRIC *) Object;
- VECTOR New_Point;
- register DBL Result, Linear_Term, Square_Term;
-
- VDot (Linear_Term, *IPoint, Quadric->Terms);
- Result = Linear_Term + Quadric->Constant;
- VSquareTerms (New_Point, *IPoint);
- VDot (Square_Term, New_Point, Quadric->Square_Terms);
- Result += Square_Term;
- Result += Quadric->Mixed_Terms.x * (IPoint->x) * (IPoint->y)
- + Quadric->Mixed_Terms.y * (IPoint->x) * (IPoint->z)
- + Quadric->Mixed_Terms.z * (IPoint->y) * (IPoint->z);
-
- if (Result < Small_Tolerance)
- return (TRUE);
-
- return (FALSE);
- }
-
- void Quadric_Normal (Result, Object, IPoint)
- VECTOR *Result, *IPoint;
- OBJECT *Object;
- {
- QUADRIC *Intersection_Quadric = (QUADRIC *) Object;
- VECTOR Derivative_Linear;
- DBL Len;
-
- VScale (Derivative_Linear, Intersection_Quadric->Square_Terms, 2.0);
- VEvaluate (*Result, Derivative_Linear, *IPoint);
- VAdd (*Result, *Result, Intersection_Quadric->Terms);
-
- Result->x +=
- Intersection_Quadric->Mixed_Terms.x * IPoint->y +
- Intersection_Quadric->Mixed_Terms.y * IPoint->z;
-
-
- Result->y +=
- Intersection_Quadric->Mixed_Terms.x * IPoint->x +
- Intersection_Quadric->Mixed_Terms.z * IPoint->z;
-
- Result->z +=
- Intersection_Quadric->Mixed_Terms.y * IPoint->x +
- Intersection_Quadric->Mixed_Terms.z * IPoint->y;
-
- Len = Result->x * Result->x + Result->y * Result->y + Result->z * Result->z;
- Len = sqrt(Len);
- if (Len == 0.0)
- {
- /* The normal is not defined at this point of the surface. Set it
- to any arbitrary direction. */
- Result->x = 1.0;
- Result->y = 0.0;
- Result->z = 0.0;
- }
- else
- {
- Result->x /= Len; /* normalize the normal */
- Result->y /= Len;
- Result->z /= Len;
- }
- }
-
- void Transform_Quadric (Object, Trans)
- OBJECT *Object;
- TRANSFORM *Trans;
- {
- QUADRIC *Quadric=(QUADRIC *)Object;
- MATRIX Quadric_Matrix, Transform_Transposed;
-
- Quadric_To_Matrix (Quadric, (MATRIX *) &Quadric_Matrix[0][0]);
- MTimes ((MATRIX *) &Quadric_Matrix[0][0], (MATRIX *) &(Trans->inverse[0][0]), (MATRIX *) &Quadric_Matrix[0][0]);
- MTranspose ((MATRIX *) &Transform_Transposed[0][0], (MATRIX *) &(Trans->inverse[0][0]));
- MTimes ((MATRIX *) &Quadric_Matrix[0][0], (MATRIX *) &Quadric_Matrix[0][0], (MATRIX *) &Transform_Transposed[0][0]);
- Matrix_To_Quadric ((MATRIX *) &Quadric_Matrix[0][0], Quadric);
- }
-
- void Quadric_To_Matrix (Quadric, Matrix)
- QUADRIC *Quadric;
- MATRIX *Matrix;
- {
- MZero (Matrix);
- (*Matrix)[0][0] = Quadric->Square_Terms.x;
- (*Matrix)[1][1] = Quadric->Square_Terms.y;
- (*Matrix)[2][2] = Quadric->Square_Terms.z;
- (*Matrix)[0][1] = Quadric->Mixed_Terms.x;
- (*Matrix)[0][2] = Quadric->Mixed_Terms.y;
- (*Matrix)[0][3] = Quadric->Terms.x;
- (*Matrix)[1][2] = Quadric->Mixed_Terms.z;
- (*Matrix)[1][3] = Quadric->Terms.y;
- (*Matrix)[2][3] = Quadric->Terms.z;
- (*Matrix)[3][3] = Quadric->Constant;
- }
-
- void Matrix_To_Quadric (Matrix, Quadric)
- MATRIX *Matrix;
- QUADRIC *Quadric;
- {
- Quadric->Square_Terms.x = (*Matrix)[0][0];
- Quadric->Square_Terms.y = (*Matrix)[1][1];
- Quadric->Square_Terms.z = (*Matrix)[2][2];
- Quadric->Mixed_Terms.x = (*Matrix)[0][1] + (*Matrix)[1][0];
- Quadric->Mixed_Terms.y = (*Matrix)[0][2] + (*Matrix)[2][0];
- Quadric->Terms.x = (*Matrix)[0][3] + (*Matrix)[3][0];
- Quadric->Mixed_Terms.z = (*Matrix)[1][2] + (*Matrix)[2][1];
- Quadric->Terms.y = (*Matrix)[1][3] + (*Matrix)[3][1];
- Quadric->Terms.z = (*Matrix)[2][3] + (*Matrix)[3][2];
- Quadric->Constant = (*Matrix)[3][3];
- }
-
- void Translate_Quadric (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
-
- Compute_Translation_Transform (&Trans, Vector);
- Transform_Quadric (Object, &Trans);
-
- }
-
- void Rotate_Quadric (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
-
- Compute_Rotation_Transform (&Trans, Vector);
- Transform_Quadric (Object, &Trans);
- }
-
- void Scale_Quadric (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
-
- Compute_Scaling_Transform (&Trans, Vector);
- Transform_Quadric (Object, &Trans);
- }
-
- void Invert_Quadric (Object)
- OBJECT *Object;
- {
- QUADRIC *Quadric = (QUADRIC *) Object;
-
- VScaleEq (Quadric->Square_Terms, -1.0);
- VScaleEq (Quadric->Mixed_Terms, -1.0);
- VScaleEq (Quadric->Terms, -1.0);
- Quadric->Constant *= -1.0;
- }
-
- QUADRIC *Create_Quadric()
- {
- QUADRIC *New;
-
- if ((New = (QUADRIC *) malloc (sizeof (QUADRIC))) == NULL)
- MAError ("quadric");
-
- INIT_OBJECT_FIELDS(New, QUADRIC_OBJECT, &Quadric_Methods)
- Make_Vector (&(New->Square_Terms), 1.0, 1.0, 1.0);
- Make_Vector (&(New->Mixed_Terms), 0.0, 0.0, 0.0);
- Make_Vector (&(New->Terms), 0.0, 0.0, 0.0);
- New->Constant = 1.0;
- New->CM_Constant = HUGE_VAL;
- New->Constant_Cached = FALSE;
- New->Non_Zero_Square_Term = FALSE;
- return (New);
- }
-
- void *Copy_Quadric (Object)
- OBJECT *Object;
- {
- QUADRIC *New;
-
- New = Create_Quadric ();
- *New = *((QUADRIC *) Object);
-
- return (New);
- }
-
- void Destroy_Quadric (Object)
- OBJECT *Object;
- {
- free (Object);
- }
-